1986-Club80-17, S27-32

Z80, HD64180 und Illegals im ROM-Modus

Das Herz unseres kleinen Haufens Silikonmasse besteht bekanntermaßen aus einem Z80. Dieser Z80 kann über 1100 Befehle verarbeiten, von denen aber nur 694 von den Erbauern vorgesehen waren. Der Rest ist also Abfallprodukt.

Nun gibt es einen neuen Prozessor, den HD64180, der Z80-kompatibel ist, aber einige Sachen mehr kann (512Kb RAM verwalten. DMA, Schnittstelle...). Nur haben die Erbauer dieses Dings leider vergessen, die Befehle des Z80 zu berücksichtigen, die nicht offiziell dokumentiert sind. Das kann böse Probleme geben, denn wenn der neue Proz auf einen ihm unbekannten Befehl trifft, macht er einen Brutalo-Reset nach 0000h, was in unserem Fall jedes Programm ins Jenseits befördert.

Es wäre dies kein Problem, wenn niemand die "Illegals" bzw. die nicht dokumentierten Befehle benutzen würde, aber viele Programmierer tun es doch. Prominentes Beispiel der Editor/Assembler ZEUS (3 Illegals).

Ihr könnt nun

  1. den neuen Prozessor vergessen (sehr schwer!),
  2. alle Programme mit Illegals vergessen (nicht ganz so schwer),
  3. alle Illegals durch normale Befehle ersetzen (schwer) oder
  4. dem HD64180 die unbekannten Befehle beibringen (fast leicht).

Punkt 3 erschien mir brauchbar, bis sich ZEUS nach den Änderungen so merkwürdig benahm. Leider sind die Ersatz-Befehle für die Illegals nämlich einen kleinen Tick länger als die Illegals und das gibt big problems.

Also auf zu Punkt 4! Vorraussetzung: Veränderliches RAM/ROM bei 0000h: bei jedem CP/M-fähigen Rechner der Fall.

Außerdem habe ich in meinem kleinen Programm noch einiges ausgenutzt: Arnulf hett seggt1, daß RST 00h nie gebraucht wird. Also benutze man RST 00h für etwas anderes. In diesem Fall bot sich ein Banking an, das Helmuts alten Banker simuliert. Verfahrensweise: Der Speicher von 8000h-ffffh wird als Common 1 definiert und je nach gewünschter Bank wird der Offset von Common 1 neu gesetzt. Bank 0 ist die normale Bank, also sind dann Interrupts erlaubt. Ansonsten werden die Interrupts gesperrt. Die Bank-Nr. wird vor dem RST 00h in A geladen. Mein kleiner IIs kennt ein Parallel-RAM. D.h. Neben Tastatur. Bildschirm etc., die ja memory-mapped-I/O sind, gibt es einen RAM-Bereich von 3400h-3fffh. Je nach Wunsch kann ich nun entweder Ein-/Ausgaben vornehmen oder in diesem Extra-RAM einige zusätzliche Programme laufen lassen. Wiederum müßte jeder TRS80-CP/M-Rechner irgendetwas in der Richtung haben.

Nun versteht Ihr auch, warum ich in der Überschrift von "ROM-Modus" sprach. Der ganze Kram klappt bei CP/M in dieser Form nicht. Dafür andere Lösungen zu suchen, überlasse ich den CP/M-Freaks.

Zu guter Letzt kann ich auch das ROM/RAM überschreiben (s. wiederum CP/M-fähige Rechner). Da sich in dem ROM allerhand Müll angesammelt hat kann man gewisse Teile ohne Skrupel killen, was ich auch getan habe.

Mit diesen ganzen Einschränkungen wird das Programm zwar sehr auf eine Maschine festgelegt, aber wer wird sich schon einen HD64180 anschaffen? Wohl doch nur Leute, die sowieso am Satteln sind und bei deren Drahtansammlungen nicht viel vom TRS80 übrig geblieben ist.

Noch kurz zum eigentlichen Programm: Der erste Teil ist nur der Ansprung der Routine von 0C00h aus. Der zweite Teil ist ein Ausgang aus der Routine, bei dem die Interrupts ausgeschaltet bleiben. Die anderen Ein/Aus-Routinen stellt OVL3/SYS aus dem Gdos 2.4 zur Verfügung. Der dritte Teil ist derjenige, der beim Aufruf die Routine ins Parallel-RAM bringt. Danach folgt die eigentliche Routine, die im gegenwärtigen Zustand noch nicht mal 100h Bytes lang ist. Sie berücksichtigt alle Illegals, die in einen Artikel der "data welt" in Mai/Juni 1986 erwähnt wurden. Die HD64180-spezifischen Befehle IN0/OUT0 wurden über DBs realisiert, weil mein alter ZEUS sie natürlich nicht kennt.

Der Programmierstil ist leider sehr "unschön", wie mein Prof sagen würde, vor allem aufgrund der vielen Patches direkt im Programmablauf, aber es tut seinen Dienst.

Gerald Schröder Hardware: Helmut Bernhardt Literatur: "TAV’s Z80 Tuning" aus "data welt" 5 und 6 ’86 Z80-Reference-Manual

		00001 ;	Error-Trap für Genie IIs mit HD64180
		00002 ;	Weihnachten ’86 by Gerald Schröder
		00003
		00004
	06A0	00005 pramon	EQU	06a0h		;schaltet Par.-RAM ein
	06AB	00006 pramoff	EQU	06abh		;schaltet Par.-RAM aus
		00007
		00008
		00009 ;	
		00010
		00011 ; 0000: Ansprung Error-Trap und RST 00h
		00012
0000		00013		ORG	0
0000	CDA006	00014		CALL	pramon		;Par.-RAM ein
0003	C30034	00015		JP	routin-offset	;anspringen
		00016
		00017
		00018	;	
		00019
		00020	;	neuer Ausgang: Par.-RAM aus und Interrupts
		00021	;	bleiben disabled
		00022
06D2		00023		ORG	06d2h
06D2	DBFE 	00024 prama	IN	A,(0feh)
06D4	CB87 	00025		RES	0,A
06D6	D3FE 	00026		OUT	(0feh),A
06D8	F1	00027		POP	AF
06D9	C9	00028		RET
		00029
		00030
		00031	;	
		00032
		00033	;	Initialisierungsroutine
		00034
5200		00035		ORG	5200H
5200	3E80	00036 start	LD	A,80h		;Common 1 ab 8000h
5202	ED	00037		DB	0edh,39h,3ah 	;setzen (OUT0 (3ah),A)
		00038
5205	CDA006 	00039 		CALL	pramon		;Par.-RAM ein
5208	211652 	00040		LD	HL,routin	;Routine
520B	110034 	00041		LD	DE,routin-offset ;dorthin
520E	01C900 	00042		LD	BC,ende-routin	;übertragen
5211	EDB0	00043		LDIR
5213	C3AB06	00044		JP	pramoff 	;Par.-RAM aus und ab
		00045
		00046
		00047	;	
		00048
		00049	;	Routine im Par.-RAM für Error-Trap und RST 00h
		00050	;	bei Error: fehlende Codes simulieren
		00051	;	bei RST 00h: Bank A einschalten
		00052
1E16		00053 offset	EQU	$-3400h
5216	F5	00054 routin	PUSH	AF
5217	ED	00055		DB	0edh,38h,34h	;IN0 A,(34h)
521A	CB7F	00056		BIT	7,A		;TRAP gesetzt?
521C	2010	00057		JR	NZ,illopc	;ja, illegaler Opcode
		00058				
		00059	;*******************************
		00060	;* Banking; Bank A einschalten *
		00061	;*******************************
		00062
521E	F1	00063		POP	AF
521F	F5	00064		PUSH	AF 		;retten
5220	07	00065		RLCA
5221	07	00066		RLCA			;korr. Offset erzeugen
5222	07	00067		RLCA			;(Basis Common 1 neu)
5223	ED	00068		DB	0edh,39h,38h	;OUT0 (38h),A
5226	B7	00069		OR	A 		;Bank 0?
5227	C2D206 	00070		JP	NZ,prama	;nein, keine Interrupts
522A	F1	00071		POP	AF
522B	C3AB06 	00072		JP	pramoff 	;Interrupts ein
		00073
		00074
		00075
		00076	;*********************************
		00077	;* illegaler Opcode: simulieren  *
		00078	;*********************************
		00079
522E	CBBF	00080 illopc	RES	7,A 		;TRAP löschen
5230	ED	00081		DB	0edh,39h,34h	;OUT0 (34h),A
5233	322534 	00082		LD	(ufo-offset),A 	;UFO retten
5236	F1	00083		POP	AF 		;A vom Stack
5237	E3	00084		EX	(SP),HL 	;HL mit Err.-Adr. tausch
5238	F5	00085		PUSH	AF 		;A wieder retten
5239	C5	00086		PUSH	BC 		;BC als Hilfsregister
523A	3E00	00087		LD	A,0 		;UFO
523B		00088 ufo	EQU	$-1
523C	CB77	00089		BIT	6,A 		;gesetzt?
523E	2801	00090		JR	Z,nosub 	;nein, Opc. direkt davor
5240	2B	00091		DEC	HL
5241	2B	00092 nosub	DEC	HL 		;Zeiger auf ill. Opc.
5242	7E	00093		LD	A,(HL) 		;laden
5243	47	00094		LD	B,A 		;und retten
5244	FECB	00095		CP	0cbh		;CBxx? (SLIA)
5246	23	00096		INC	HL 		;Zeiger weiter
5247	7E	00097		LD	A,(HL) 		;2. Byte laden
5248	200F	00098		JR	NZ,ddfd 	;nein, Oper. mit IX/Y
		00099
		00100	;***********************************
		00101	;* illegaler Opcode; CBxx = SLIA x *
		00102	;***********************************
		00103
524A	D620	00104		SUB	20h 		;korrigieren
524C	323F34 	00105		LD	(CBxx-offset),A ;in den Programm-Text
		00106
524F	C1	00107		POP	BC 		;Register zurück
5250	F1	00108		POP 	AF
5251	23	00109		INC	HL 		;PC neu setzen
5252	E3	00110		EX	(SP),HL 	;und HL zurück
5253	37	00111		SCF			;für invertiert!!!
5254	CB10	00112		RL	B		;und rotieren
5255		00113 CBxx	EQU 	$-1 		;10-17 für Register B-A
5256	C3AB06 	00114 ab	JP	pramoff 	;weiter im Programm
		00115
		00116
		00117	;***************************************
		00118	;* illegaler Opcode: erstes Byte DD/FD *
		00119	;***************************************
				00120
5259	FECB	00121 ddfd	CP 	0cbh		;danach CBh?
525B	2828	00122		JR 	Z,ddfdcb	;ja
525D	326834	00123		LD 	(ersatz-offset),A 	;in den Text
5260	FE26	00124		CP	26h		;"LD hX/Y, konstante"?
5262	2807	00125		JR 	Z,ldkon		;ja
5264	FE2E	00126		CP 	2eh		;"LD IX/Y, konstante"?
5266	2803	00127		JR 	Z,ldkon		;ja
		00128
5268	AF	00129		XOR 	A 		;keine Konstante; NOP
5269	1802	00130		JR	weiter
		00131
		00132	;	Konstante nach MSB/LSB von IX/Y
		00133
526B	23	00134 ldkon	INC	HL 		; Zeiger auf Konstante
526C	7E	00135		LD 	A,(HL) 		;diese laden
		00136
526D	326934 	00137 weiter	LD	(konst-offset),A 	;u. in den Text
5270	78	00138		LD	A,B 			;DD/FD zurück
5271	326534 	00139		LD 	(ddfd1-offset),A	;setzen
5274	326B34	00140		LD 	(ddfd2-offset),A
		00141
5277	C1	00142		POP	BC 		;alle Register zurück
5278	F1	00143		POP	AF
5279	23	00144		INC	HL 		;PC neu
527A	E3	00145		EX	(SP),HL 	;HL zurück
		00146
527B	DDE5	00147 ddfd1	PUSH	IX 		;bzw. IY
527D	E3	00148		EX	(SP),HL 	;nach HL
527E	7F	00149 ersatz LD 	A,A 		;Operation ausführen
527F	00	00150 konst	NOP 			;evtl. Konstante
5280	E3	00151		EX	(SP),HL 	;neues IX/Y zurück
5281	DDE1	00152 ddfd2 POP		IX 		;bzw. IY
5283	18D1	00153		JR	ab
		00154
		00155
		00156	;*************************************
		00157	;* DD/FD gefolgt von CB		     *
		00158	;* RLC/RRC/RL/RR/SLA/SRA/(SLIA)/SRL, *
		00159	;* (IX/Y+d),B/C/D/E/H/L/A	     *
		00160	;*************************************
		00161
5285	78	00162 ddfdcb	LD	A,B		;DD/FD zurück
5286	32C034 	00163		LD	(ddfd3-offset),A ;setzen
5289	32C534 	00164		LD	(ddfd4-offset),A
528C	23	00165		INC	HL 		;Zeiger auf Offset
528D	7E	00166		LD	A,(HL) 		;"d" aus (IX/Y+d) laden
528E	32C234 	00167		LD	(offs1-offset),A ;setzen
5291	32C734 	00168		LD	(offs2-offset),A
5294	23	00169		INC	HL 		;Zeiger auf Operation
		00170
		00171	;	Lade-Befehl errechnen und in den Text
		00172
5295	7E	00173		LD	A,(HL) 		;Befehl laden
5296	E607	00174		AND	7		;nur die Bits 0-2
5298	3C	00175		INC	A		;+1
5299	47	00176		LD	B,A		;als Zähler
529A	3E3E	00177		LD	A,3eh		;Opcode 46h-7eh erzeugen
00178
529C	C608	00179 loop1 ADD		A,8				;(46/4e/56/5e/66/6e/7e)
529E	10FC	00180		DJNZ	loop1		;=LD B/C/D/E/H/L/A, (IX..)
52A0	32C634 	00181		LD	(lade-offset),A ;setzen
		00182
		00183	;	Rotations-/Schiebe-Befehl erzeugen
		00184
52A3	7E	00185		LD	A,(HL)
52A4	E6F8	00186		AND	0f8h		;die Bits 0-2 löschen
52A6	0F	00187		RRCA			;und raus rotieren
52A7	0F	00188		RRCA
52A8	0F	00189		RRCA
52A9	3C	00190		INC	A		;+1
52AA	47	00191		LD	B,A		;als Zähler
52AB	3EFE	00192		LD	A,0feh		;6/e/16/le/26/2e/3e=RLC,
00193
52AD	C608	00194 loop2	ADD		A,8				;RRC,RL,RR,SLA,SRA,SRL
52AF	10FC	00195		DJNZ	loop2		;(u. RES/SET x)
		00196
52B1	48	00197		LD	C,B 		;NOP erzeugen (für reta)
		00198
52B2	FE36	00199		CP	36h		;SLIA?
52B4	200B	00200		JR	NZ,noSLIA	;nein
		00201
		00202	;	SLIA (IX/Y+d) oder SLIA (IX/Y+d),r
		00203
52B6	0637	00204		LD	B,37h		;SCF erzeugen
52B8	7E	00205		LD	A,(HL)		;SLIA (IX/Y+d)?
52B9	FE36	00206		CP	36h
52BB	2002	00207		JR	NZ,nopro	;nein, kein Problem
52BD	0EC9	00208		LD	C,0c9h		;RET für reta erzeugen
		00209
52BF	3E16	00210 nopro	LD	A,16h		;RL erzeugen (statt SLIA)
		00211
52C1	32C334 	00212 noSLIA	LD	(opera-offset),A ;setzen
52C4	78	00213		LD	A,B		;SCF oder NOP
52C5	32BF34 	00214		LD	cflag-offset),A	;setzen
52C8	79	00215		LD	A,C		;RET oder NOP
52C9	32C434 	00216		LD	(reta-offset),A ;setzen
		00217
52CC	C1	00218		POP	BC		;Register zurück
52CD	F1	00219		POP	AF
52CE	23	00220		INC	HL		;PC korrigieren
52CF	E3	00221		EX	(SP),HL		;und HL zurück
		00222
52D0	CDBF34 	00223		CALL	cflag-offset	;Operation ausführen
52D3	1881	00224		JR	ab
		00225
		00226	;	Unterprogramm; Operation simulieren
		00227
52D5	00	00228 cflag	NOP			;oder SCF
		00229
52D6	00	00230 ddfd3 	NOP			;DD o. FD für IX/Y
52D7	CB	00231		DB	0cbh		;immer CBh
52D8	00	00232 offs1	NOP			;Offset d (IX/Y+d)
52D9	00	00233 opera	NOP			;Operationsanweisung
		00234
52DA	00	00235 reta	NOP			;RETurn bei SLIA (IX/Y+d)
		00236
52DB	00	00237 ddfd4	NOP			;DD/FD für IX/Y
52DC	7F	00238 lade	LD	A,A		;Ladebefehl
52DD	00	00239 offs2	NOP			;Offset (s. offs1)
52DE	C9	00240		RET
		00241
52DF		00242 ende	EQU	$
00243
00244
5200		00245		END	start
1 hett seggt = plattdeutsch oder auch umgangssprachlicher Ausdruck für "hat gesagt"